#pragma once
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <queue>
using namespace std;

template<class T>
class BlockQueue
{
    static const int NUM = 10;
public:
    BlockQueue(int num = NUM) : _max(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_pCond, nullptr);
        pthread_cond_init(&_cCond, nullptr);
    }

    const T pop()
    {
        pthread_mutex_lock(&_mutex);
        if(_q.size() == 0) {
            // 队列中没有值，不需要再删除了，让它去等待队列中去等
            pthread_cond_wait(&_cCond, &_mutex);
        }
        const T x = _q.front();
        _q.pop();
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_pCond);   // 消费者已经消费数据了，此时就可以唤醒生产者了。
        return x;
    }

    void push(const T& x)
    {   
        pthread_mutex_lock(&_mutex);
        if(_q.size() == _max) {
            // 已经到了最大值，不需要再添加了，让它去等待队列中去等
            pthread_cond_wait(&_pCond, &_mutex);
        }
        _q.push(x);
        pthread_mutex_unlock(&_mutex);  
        pthread_cond_signal(&_cCond);   // 生产者已经生产数据了，此时就可以唤醒消费者了。

    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pCond);
        pthread_cond_destroy(&_cCond);
    }

private:
    queue<T> _q;
    pthread_mutex_t _mutex;
    pthread_cond_t _cCond;  // 消费者条件变量
    pthread_cond_t _pCond;  // 生产者条件变量
    size_t _max;    // 队列能放的最大值
};


